#include <cassert>
#include <cstdint>
#include <random>
#include <systemc.h>

constexpr uint32_t calc_sw(uint32_t N) noexcept {
    return N <= 1 ? 0 : 1 + calc_sw(N >> 1);
}

template <uint32_t N, uint32_t DW, uint32_t SW = calc_sw(N)>
SC_MODULE(Multiplexer) {
    sc_vector<sc_in<sc_uint<DW>>> inputs {"input"};
    sc_in<sc_uint<SW>> select;
    sc_out<sc_uint<DW>> output;

    void multiplex() {
        auto sel = select.read();
        assert(sel < N);
        output.write(inputs[sel].read());
    }

    SC_CTOR(Multiplexer) {
        assert(DW > 0);
        inputs.init(N);
        SC_METHOD(multiplex);
        for (auto &input : inputs) {
            sensitive << input;
        }
        sensitive << select;
    }
};

int sc_main(int, char *[]) {
    const int N = 4, DW = 8;
    const int SW = calc_sw(N);
    
    sc_signal<sc_uint<SW>> select;
    sc_signal<sc_uint<DW>> output;
    sc_vector<sc_signal<sc_uint<DW>>> inputs("input", N);

    Multiplexer<N, DW> mux("mux");
    mux.select(select);
    mux.output(output);
    for (int i = 0; i < N; i++) {
        mux.inputs[i](inputs[i]);
    }

    // 随机数生成
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(0, 0xFF);

    // [波形追踪]
    sc_trace_file *tf = sc_create_vcd_trace_file("multiplexer");
    tf->set_time_unit(1, SC_NS); // 设置时间单位为 1 ns
    sc_trace(tf, select, "select");
    sc_trace(tf, output, "output");
    for (int i = 0; i < 4; i++) {
        sc_trace(tf, inputs[i], "input" + std::to_string(i));
    }

    // [施加激励]
    for (int i = 0; i < 100; i++) {
        select.write(dis(gen) % N);
        for (int j = 0; j < N; j++) {
            inputs[j].write(dis(gen));
        }
        sc_start(1, SC_NS);
    }

    sc_close_vcd_trace_file(tf);

    return 0;
}
